package de.tabuma.logging.logik;

import java.util.*;
import java.util.logging.*;

import java.lang.reflect.*;

import javax.jdo.*;
import javax.jdo.annotations.PrimaryKey;

/**
  * @author $Author: $
  * @version $Revision: $
  * @since $Date: $
 */
public class PMF {

    private static final Logger log = Logger.getLogger(PMF.class.getName());
    private static final PersistenceManagerFactory pmfInstance = JDOHelper.getPersistenceManagerFactory("logging-transaction");
    private PMF() {}

    public static PersistenceManagerFactory get() {
        return pmfInstance;
    }

    /**
     * Method to persist an entity object
     * @param <T> Class of Entity Object
     * @param object Object that will be persisted
     * @return Id of the created object
     */
    public static <T> long doCreate(T object) {
        Long id = new Long(0);
        try {
            PersistenceManager pm = PMF.get().getPersistenceManager();
            pm.makePersistent(object);
            if(log.getLevel()==Level.FINE || log.getLevel()==Level.FINEST) {
                log.fine("create object "+ObjectMethods.toString(object));
            }
            for(int i=0;i<object.getClass().getDeclaredFields().length;i++) {
                Field field = object.getClass().getDeclaredFields()[i];
                PrimaryKey primaryKey = field.getAnnotation(PrimaryKey.class);
                log.finest("field "+field.getName()+" has annotation:" + primaryKey);
                if(primaryKey!=null) {
                    id = (Long) object.getClass().getMethod(ObjectMethods.getGetter(field.getName())).invoke(object);
                    i = object.getClass().getFields().length;
                }
            }
            pm.close();
        }
        catch(Exception e) {
            String a = "";
            try { a = ObjectMethods.toString(object); } catch(Exception e1) {}
            log.warning(e.getMessage() + " at " + object + "(" + a + ")");
            String warning = "";
            for(int i=0;i<e.getStackTrace().length;i++) {
                warning += e.getStackTrace()[i]+"\n";
            }
            log.warning(warning);
        }
        return id;
    }

    /**
     * Method
     * @param <T> Class of Entity Object
     * @param object Object that will be persisted
     * @return Id of the created object
     */
    public static <T> long doRemove(T object) {
        Long id = new Long(0);
        try {
            PersistenceManager pm = PMF.get().getPersistenceManager();
            pm.deletePersistent(object);
        }
        catch(Exception e) {
            String a = "";
            try { a = ObjectMethods.toString(object); } catch(Exception e1) {}
            log.warning(e.getMessage() + " at " + object + "(" + a + ")");
            String warning = "";
            for(int i=0;i<e.getStackTrace().length;i++) {
                warning += e.getStackTrace()[i]+"\n";
            }
            log.warning(warning);
        }
        return id;
    }

    /**
     * Method get object.
     * @param <T> Class of entity object
     * @param id ID
     * @return Object
     */
    public static <T> T get(long id,T object) {
        try {

            PersistenceManager pm = PMF.get().getPersistenceManager();
            Query query = pm.newQuery(object.getClass());
            String fieldName = "id";
            for(int i=0;i<object.getClass().getDeclaredFields().length;i++) {
                Field field = object.getClass().getDeclaredFields()[i];
                PrimaryKey primaryKey = field.getAnnotation(PrimaryKey.class);
                log.finest("field "+field.getName()+" has annotation:" + primaryKey);
                if(primaryKey!=null) {
                    fieldName = field.getName();
                    i = object.getClass().getFields().length;
                }
            }

            query.setFilter(fieldName + " == " + id);
            List<T> list = (List<T>)query.execute();
            if(list.size()>0) {
                object = list.get(0);
            }
            query.closeAll();
            pm.close();
            if(log.getLevel()==Level.FINE || log.getLevel()==Level.FINEST) {
                log.fine("id:"+id+";"+ObjectMethods.toString(object));
            }
        }
        catch(Exception e) {
            log.warning(e.getMessage()+" at "+object);
            String warning = "";
            for(int i=0;i<e.getStackTrace().length;i++) {
                warning += e.getStackTrace()[i]+"\n";
            }
            log.warning(warning);
        }
        return object;
    }

    /**
     * Method get object.
     * @param <T> Class of entity object
     * @param key list of keys that will be used as filter
     * @param value list of values that will be used as filter
     * @return Object
     */
    public static <T> List<T> get(String key[], String value[],T object) {
        try {
            PersistenceManager pm = PMF.get().getPersistenceManager();
            Query query = pm.newQuery(object.getClass());
            
            String filter = "";
            if(key!=null && value!=null) {
                if(key.length==value.length) {
                    for(int i=0;i<key.length;i++) {
                        if(i!=0) {
                            filter += " && ";
                        }
                        filter += key[i]+"=="+value[i];
                    }
                }
            }

            query.setFilter(filter);
            List<T> list = (List<T>)query.execute();
            ArrayList<T> list1 = new ArrayList<T>();

            for(int i=0;i<list.size();i++) {
                list1.add(list.get(i));
            }
            query.closeAll();
            pm.close();
            
            if(log.getLevel()==Level.FINE || log.getLevel()==Level.FINEST) {
                log.fine("filter:"+filter+";"+ObjectMethods.toString(object));
            }
            return list1;
        }
        catch(Exception e) {
            log.warning(e.getMessage()+" at "+object);
            String warning = "";
            for(int i=0;i<e.getStackTrace().length;i++) {
                warning += e.getStackTrace()[i]+"\n";
            }
            log.warning(warning);
        }
        return null;
    }

    /**
     * Method to update object.
     * @param <T> Class of entity object
     */
    public static <T> void doUpdate(T object) {
        Long id = null;
        String fieldName = "id";
        try {
            log.fine(object.toString());
            //Finding id
            for(int i=0;i<object.getClass().getDeclaredFields().length;i++) {
                Field field = object.getClass().getDeclaredFields()[i];
                PrimaryKey primaryKey = field.getAnnotation(PrimaryKey.class);
                if(primaryKey!=null) {
                    log.fine("field "+field.getName()+" has annotation:" + primaryKey);
                    id = (Long) object.getClass().getMethod(ObjectMethods.getGetter(field.getName())).invoke(object);
                    fieldName = field.getName();
                    i = object.getClass().getFields().length;
                }
            }
            PersistenceManager pm = PMF.get().getPersistenceManager();
            Query query = pm.newQuery(object.getClass());
            query.setFilter(fieldName + " == " + id);
            List<T> list = (List<T>)query.execute();
            if(list.size()>0) {
                T object1 = list.get(0);
                ObjectCopyFacade.copy(object,object1);
                if(log.getLevel()==Level.FINE || log.getLevel()==Level.FINEST) {
                    String logText = "obj1:"+ObjectMethods.toString(object);
                    log.fine(logText);
                }
            }
            else {
                log.warning(object + " width " + fieldName + " = " + id + " has no values.");
                doCreate(object);
            }
            query.closeAll();
            pm.close();
        }
        catch(Exception e) {
            log.warning(e.getMessage()+ " at "+object+"(id="+id);
            String warning = "";
            for(int i=0;i<e.getStackTrace().length;i++) {
                warning += e.getStackTrace()[i]+"\n";
            }
            log.warning(warning);
        }
    }
}
